use std::time::Duration;

use reqwest::header::{HeaderMap, HeaderValue};

use crate::{core::cluster::CLUSTER, error};

use super::{config::{SERVER_URL, TOKEN}, file_content::FileContent};

#[derive(serde::Deserialize, Debug)]
pub struct ResponseContent<T> {
	pub status: i32,
	pub msg: String,
	pub data: T,
}

#[derive(serde::Deserialize, Debug)]
pub struct ClusterUpdateResp {
	pub latest_version: String,
	pub update_content: Vec<FileContent>,
}

#[derive(serde::Deserialize, Debug)]
pub struct ClusterLatestResp {
	pub latest_version: String,
	pub file_content: Vec<FileContent>,
}

fn clone_server_url() -> String {
	SERVER_URL.lock().unwrap().clone()
}

async fn get(path: &String) -> String {
	let mut url = clone_server_url();
	let token = TOKEN.lock().unwrap();
	let token = token.to_string();

	url.push_str(path);
	let mut headers = HeaderMap::new();
	headers.insert("Authorization", HeaderValue::from_str(token.as_str()).unwrap());

	let client = reqwest::Client::builder()
		.timeout(Duration::from_secs(10))
		.default_headers(headers)
		.build()
		.unwrap();

	let resp = client.get(url).send().await.unwrap();
	if resp.status() == 403 {
		error!(format!("request failed: invalid TOKEN={}", token));
	}

	if resp.status() != 200 {
		error!(format!("request failed: {}", resp.status()));
	}

	resp.text().await.unwrap()
}

// pub async fn get_latest() -> Result<Vec<FileContent>, ()> {
pub async fn get_latest() -> ClusterLatestResp {
	let mut path = String::from("/latest/");
	path.push_str(CLUSTER.lock().unwrap().name.as_str());
	let resp = get(&path).await;
	println!("{}", resp);
	let resp: ResponseContent<ClusterLatestResp> = serde_json::from_str(resp.as_str()).unwrap();
	if resp.status != 0 {
		error!(resp.msg);
	}

	resp.data
}

pub async fn get_update(old_version: &String) -> ClusterUpdateResp {
	let path = format!("/update/{}/{}", CLUSTER.lock().unwrap().name, old_version);
	let resp = get(&path).await;
	let resp: ResponseContent<ClusterUpdateResp> = serde_json::from_str(&resp.as_str()).unwrap();
	if resp.status != 0 {
		error!(resp.msg);
	}

	resp.data
}
